package com.inno.life.domain.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONObject;
import com.inno.life.common.constant.MessageTypeConstant;
import com.inno.life.common.constant.RocketMQConstant;
import com.inno.life.common.enums.LikedTypeEnum;
import com.inno.life.common.enums.YesOrNoEnum;
import com.inno.life.common.error.BusinessException;
import com.inno.life.common.utils.DateUtils;
import com.inno.life.domain.dict.Constant;
import com.inno.life.domain.entity.LikedMessageBO;
import com.inno.life.domain.entity.MomentLikedBO;
import com.inno.life.domain.redis.RedisUtil;
import com.inno.life.domain.service.MomentLikedDomainService;
import com.inno.life.domain.websocket.ZeyPlannerSocket;
import com.inno.life.infra.basic.entity.PlannerMessages;
import com.inno.life.infra.basic.entity.PlannerMoment;
import com.inno.life.infra.basic.service.PlannerMessagesService;
import com.inno.life.infra.basic.service.PlannerMomentLikedService;
import com.inno.life.infra.basic.service.PlannerMomentService;
import com.inno.life.infra.entity.UserInfo;
import com.inno.life.infra.rpc.UserRpc;
import jakarta.websocket.Session;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.bouncycastle.dvcs.VPKCRequestBuilder;
import org.slf4j.Logger;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.net.Socket;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author sean
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class MomentLikedDomainServiceImpl implements MomentLikedDomainService {
    private final PlannerMomentLikedService plannerMomentLikedService;
    private final PlannerMomentService plannerMomentService;
    private final ZeyPlannerSocket zeyPlannerSocket;
    private final RedisUtil redisUtil;
    private static final ReentrantLock LOCK = new ReentrantLock();
    private final ThreadPoolTaskExecutor lifeExecutor;
    private final RocketMQTemplate rocketMQTemplate;
    private final PlannerMessagesService plannerMessagesService;

    private final UserRpc userRpc;

    @Override
    public void add(MomentLikedBO momentLikedBO) {
        Long toMomentId = momentLikedBO.getToMomentId();
        Long fromId = momentLikedBO.getFromId();
        LOCK.lock();
        try {
            List<Object> likedInfoList = redisUtil.lGet(Constant.CacheKey.LIKED_CACHE_PREFIX + toMomentId);
            // 转为Long的集合
            if (CollectionUtil.isNotEmpty(likedInfoList)){
                List<Long> likedUserIdList = likedInfoList.stream().map(l-> Long.valueOf(l.toString())).toList();
                if (CollectionUtil.isNotEmpty(likedInfoList) && likedUserIdList.contains(fromId)) {
                    // 移除已点赞数据
                    redisUtil.lRemove(Constant.CacheKey.LIKED_CACHE_PREFIX + toMomentId, 0, fromId);
                    long decr = redisUtil.decr(Constant.CacheKey.MOMENT_LIKED_COUNT + toMomentId, 1);
                    if (decr == 0) {
                        redisUtil.del(Constant.CacheKey.MOMENT_LIKED_COUNT + toMomentId);
                    }
                    this.sendMessage(toMomentId, fromId,LikedTypeEnum.CANCEL.getType());
                    return;
                }
            }
            // 点赞
            redisUtil.lSet(Constant.CacheKey.LIKED_CACHE_PREFIX + toMomentId, momentLikedBO.getFromId());
            // 处理点赞数量
            Object count = redisUtil.get(Constant.CacheKey.MOMENT_LIKED_COUNT + toMomentId);
            if (Objects.isNull(count)) {
                redisUtil.set(Constant.CacheKey.MOMENT_LIKED_COUNT + toMomentId, 1);
            } else {
                redisUtil.incr(Constant.CacheKey.MOMENT_LIKED_COUNT + toMomentId, 1);
            }
            this.sendMessage(toMomentId, fromId,LikedTypeEnum.LIKE.getType());
        } catch (Exception e) {
            boolean retrySuccess = this.retryRedis(momentLikedBO);
            if (!retrySuccess) {
                log.error("点赞失败，用户id为：{}，动态id为：{}", fromId, toMomentId);
                throw new BusinessException("操作失败,请稍后重试!");
            }
        } finally {
            LOCK.unlock();
        }
        this.asyncSaveMessageAndSendWebSocketMessage(fromId,toMomentId);


    }
    private void asyncSaveMessageAndSendWebSocketMessage(Long fromId , Long toMomentId){
        CompletableFuture.runAsync(()->{
            PlannerMoment plannerMoment = this.plannerMomentService.queryById(toMomentId);
            Long userId = plannerMoment.getUserId();
            if (userId.equals(fromId)){
                return;
            }

            JSONObject message = buildMessageJson(plannerMoment);
            saveMessage(fromId,userId);
            sendWebsocketMessage(message,userId,zeyPlannerSocket);
        },lifeExecutor);
    }

    private static void sendWebsocketMessage(JSONObject message, Long userId, ZeyPlannerSocket zeyPlannerSocket) {
        Session session = zeyPlannerSocket.getSession(userId);
        if (session != null && session.isOpen()) {
            zeyPlannerSocket.sendMessage(session, message.toString());
        } else {
            log.warn("用户{}的socket连接已断开或不存在，无法发送点赞消息", userId);
            zeyPlannerSocket.putOfflineMessage(userId, message.toString());
        }
    }

    private static JSONObject buildMessageJson(PlannerMoment plannerMoment) {
        JSONObject message = new JSONObject();
        message.putOnce("title", "点赞消息");
        message.putOnce("type", MessageTypeConstant.LIKED_MOMENT);
        message.putOnce("message", "有人点赞了你的动态,快去看看吧");
        message.putOnce("moment", plannerMoment.getId().toString());
        return message;
    }

    private void saveMessage(Long fromId , Long userId){
        PlannerMessages plannerMessages = new PlannerMessages();
        plannerMessages.setUserId(userId);
        plannerMessages.setFromId(fromId);
        plannerMessages.setId(IdUtil.getSnowflakeNextId());
        plannerMessages.setType(Constant.MessagesType.LIKED);
        plannerMessages.setCreateTime(DateUtils.getNowDate());
        UserInfo userInfo = userRpc.getUserInfoById(fromId);
        plannerMessages.setContent("用户:" + userInfo.getUsername() + "点赞了你的发布的动态");
        plannerMessages.setIsRead(YesOrNoEnum.NO.getCode());
        plannerMessagesService.insert(plannerMessages);
    }


    /**
     * 发送MQ消息
     */
    private void sendMessage(Long toMomentId, Long fromId,Integer type) {
        LikedMessageBO likedMessageBO = new LikedMessageBO();
        likedMessageBO.setToMomentId(toMomentId);
        likedMessageBO.setFromId(fromId);
        likedMessageBO.setType(type);
        likedMessageBO.setCreateTime(DateUtils.getNowDate());
        this.rocketMQTemplate.convertAndSend(RocketMQConstant.TopicConstant.MOMENT_LIKED_TOPIC,likedMessageBO);
    }

    /**
     * 重试
     */
    private boolean retryRedis(MomentLikedBO momentLikedBO) {
        int maxRetries = 3;
        int retryCount = 0;
        while (retryCount < maxRetries) {
            try {
                Long toMomentId = momentLikedBO.getToMomentId();
                Long fromId = momentLikedBO.getFromId();

                List<Object> likedInfoList = redisUtil.lGet(Constant.CacheKey.LIKED_CACHE_PREFIX + toMomentId);
                // 转为Long的集合
                if (CollectionUtil.isNotEmpty(likedInfoList)){
                    List<Long> likedUserIdList = likedInfoList.stream().map(l-> Long.valueOf(l.toString())).toList();
                    if (CollectionUtil.isNotEmpty(likedInfoList) && likedUserIdList.contains(fromId)) {
                        // 移除已点赞数据
                        redisUtil.lRemove(Constant.CacheKey.LIKED_CACHE_PREFIX + toMomentId, 0, fromId);
                        redisUtil.decr(Constant.CacheKey.MOMENT_LIKED_COUNT + toMomentId, 1);
                        this.sendMessage(toMomentId, fromId,LikedTypeEnum.CANCEL.getType());
                        return true;
                    }
                }
                // 点赞
                redisUtil.lSet(Constant.CacheKey.LIKED_CACHE_PREFIX + toMomentId, momentLikedBO.getFromId());
                // 处理点赞数量
                Object count = redisUtil.get(Constant.CacheKey.MOMENT_LIKED_COUNT + toMomentId);
                if (Objects.isNull(count)) {
                    redisUtil.set(Constant.CacheKey.MOMENT_LIKED_COUNT + toMomentId, 1);
                } else {
                    redisUtil.incr(Constant.CacheKey.MOMENT_LIKED_COUNT + toMomentId, 1);
                }
                this.sendMessage(toMomentId, fromId,LikedTypeEnum.LIKE.getType());
                return true;
            } catch (Exception e) {
                retryCount++;
                log.error("第{}次重试Redis操作时出现异常，动态ID：{}，用户ID：{}", retryCount, momentLikedBO.getToMomentId(), momentLikedBO.getFromId(), e);
            }
        }
        return false;
    }
}
